package cn.dyw.engine.core.exec;

import cn.dyw.engine.core.context.ReportStandardContext;
import cn.dyw.engine.core.exception.EngineExecException;
import cn.dyw.engine.core.exception.EngineRenderException;
import cn.dyw.engine.core.utils.DatabaseResultSetUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @author dyw770
 * @since 2021-08-10
 */
@Slf4j
public abstract class AbstractReportExecEngine implements IReportExecEngine {

    @Override
    public ReportResult exec(ReportStandardContext context)
            throws EngineExecException {

        try (Connection connection = context.getConnection()) {

            render(context);
            if (!context.getSorts().isEmpty()) {
                sort(context);
            }
            if (!ObjectUtils.isEmpty(context.getLimit())) {
                limit(context);
            }
            if (context.isNeedPage() && !ObjectUtils.isEmpty(context.getExecPage())) {
                page(context);
            }

            return execDataQuery(context);
        } catch (EngineRenderException e) {
            throw e;
        } catch (Exception e) {
            throw new EngineExecException("执行查询过程出错, sql: [{}]", e);
        } finally {

        }
    }

    /**
     * 执行真正的查询
     *
     * @param context 参数
     */
    public ReportResult execDataQuery(ReportStandardContext context) throws EngineExecException {
        log.debug("执行sql: {}", context.getExecSql());

        try {
            ReportResult result;

            if(context.getResult() == null) {
                result = new ReportResult(context);
            } else {
                result = context.getResult();
            }

            PreparedStatement statement = context.getConnection().prepareStatement(context.getExecSql());
            ResultSet resultSet = statement.executeQuery();
            DatabaseResultSetUtils.handleResultSet(resultSet, result);
            resultSet.close();
            statement.close();

            return result;
        } catch (SQLException e) {
            throw new EngineExecException("执行SQL失败, SQL: [" + context.getExecSql() + "]", e);
        }
    }

    /**
     * 执行 sql 渲染
     * 主要是负责渲染SQL参数
     *
     * @param context 参数
     */
    public abstract void render(ReportStandardContext context) throws EngineRenderException;

    /**
     * 执行SQL排序
     *
     * @param context 参数
     */
    public abstract void sort(ReportStandardContext context) throws EngineRenderException;

    /**
     * 添加sql limit限制
     *
     * @param context 参数
     */
    public abstract void limit(ReportStandardContext context) throws EngineRenderException;

    /**
     * 添加分页逻辑
     *
     * @param context 参数
     */
    public abstract void page(ReportStandardContext context) throws EngineRenderException;
}
